#include <iostream>
#include <verilated.h>
#include <verilated_vcd_c.h>
#include "Vlicore_tb.h"

typedef Vlicore_tb dut_t;

class Testbench {
  public:
  Testbench(dut_t* dut_top, VerilatedContext* sim_context, int cycle_time=1, VerilatedVcdC* ptrace=nullptr) {
    this->top = dut_top;
    this->contextp = sim_context;
    this->tfp = ptrace;
    this->step = cycle_time/2;
  }
  void do_reset(const int wait_cycle);
  void goto_finish();

  private:
  void time_step(int step);
  void single_cycle();

  private:
    dut_t* top;
    int step;
    VerilatedContext* contextp;
    VerilatedVcdC* tfp;
};

void Testbench::time_step(int step) {
  if (tfp) tfp->dump(contextp->time());
  contextp->timeInc(step);
}

void Testbench::single_cycle() {
  top->clk = 0;
  top->eval();
  time_step(this->step);
  top->clk = 1;
  top->eval();
  time_step(this->step);
}

void Testbench::do_reset(const int wait_cycle) {
  int n = wait_cycle;
  top->rst_n = 0;
  while(n--) {
    this->single_cycle();
  };
  top->rst_n = 1;
}

void Testbench::goto_finish() {
  while (!contextp->gotFinish()) {
    single_cycle();
  }
}

int main (int argc, char** argv)
{
  VerilatedContext* contextp = new VerilatedContext;
  contextp->commandArgs(argc, argv);

  Vlicore_tb* top = new dut_t{contextp};

  VerilatedVcdC *tfp= new VerilatedVcdC;   //初始化VCD对象指针
  contextp->traceEverOn(true);            //打开追踪
  top->trace(tfp,0);
  tfp->open("sim.wave");                   //保存位置

  Testbench top_tb(top, contextp, 10, tfp);

  top_tb.do_reset(3);
  top_tb.goto_finish();

  delete top;
  delete contextp;
  return 0;
}

